// Copyright (C) 2012 Yoshiki Shibata. All rights reserved.

package main

import "net"
import "io"
import "syscall"
import "encoding/json"
import "strings"

// Message definition for JSON
type Message struct {
	Version int		`json:"version"`
	From	string	`json:"from"`
	To		string	`json:"to"`
	Message string	`json:"message"`
}

// A wrapper for the Message struct to include a remote address
type RxMessage struct {
    message     Message
    remoteAddr  string
}

type ChatListener struct {
	// Channels from the interesting modules
	channels 		[]chan RxMessage
	// All messages received will be delivered to this channel
	messageChannel	chan string
	started 		bool
}

func NewChatListener() *ChatListener {
	chatListener := new(ChatListener)
	chatListener.channels = make([]chan RxMessage, 0)
	chatListener.messageChannel = make(chan string)
	chatListener.started = false
	return chatListener
}

// Any received messages will be delivered via a channel.
// Usually a Message will be delivered to the web client, but
// It might be possible for a module to log Messages.
// This function must not be invoked once the Chat Server has started.
func (chatListener *ChatListener) AddMessageChannel(msgChan chan RxMessage) {
	if chatListener.started {
		panic("Illegal State: Server has already started")
	}
	chatListener.channels = append(chatListener.channels, msgChan)
}

func(chatListener *ChatListener) dispatchMessages() {
	var msg RxMessage

	for {
		receivedMsg := <- chatListener.messageChannel
		json.Unmarshal([]byte(receivedMsg), &(msg.message))
        remoteAddr := <- chatListener.messageChannel
        msg.remoteAddr = remoteAddr
		for i := 0; i < len(chatListener.channels); i++ {
			chatListener.channels[i] <- msg
		}
	}
}

func (chatListener *ChatListener) Start() {
	go chatListener.dispatchMessages()

	socket, e := net.Listen("tcp", ":55555")
	if e != nil {
		panic("Cannot Listen port at 55555")
	}

	for {
		conn, e := socket.Accept()
		if e != nil {
			panic("Cannot Accept")
		}

		go func() {
			defer func() {
				conn.Close()
			}()
			buffer := make([]byte, 1024)
			for {
				l, e := conn.Read(buffer)
				switch {
				case e == nil:
					chatListener.messageChannel <- string(buffer[0:l])
                    chatListener.messageChannel <- extractIPAddress(conn.RemoteAddr().String())
				case e == io.EOF:
					return
				case e != syscall.EAGAIN:
					return
				}
			}
		}()	
	}
}

func extractIPAddress(remoteAddr string) string {
    if len(remoteAddr) <= 0 {
        panic("remoteAddr is empty")
    }
    return strings.Split(remoteAddr, ":")[0]
}
